/*
two functionalities in DPGmanager:
1. deployer
2. forking a result receiver which is the sink node in the DPG
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ffs.h"
#include "cod.h"
#include "evpath.h"
#include "ev_dfg.h"
#include "util.h"
#include <math.h>
#include "cluster.h"

static EVdfg test_dfg;

/*
static char *trans = "{\
  printf(\"data \%d \\n\", input.integer_field);\n\
    return 0;\n\
}\0\0";
*/


static char *trans = "{\n\
    simple* a;\n\
    int i;\n\
    int size;\n\
    size = EVcount_simple();\n\
    printf(\"queue size \%d\\n\", size);\n\
    for(i = 0; i < size; i++) {\n\
      a = EVdata_simple(i);\n\
      printf(\"data: \%d\\n\", a.integer_field);\n\
    }\n\
    if(size == 5) {\n\
      for(i = 0; i < size; i++) {\n\
        printf(\"discard: \%d\\n\", i);\n\
        EVdiscard_simple(0);\n\
      }\n\
    }\n\
    return 0;\n\
}\0\0";

char *COD_generate = "{\n\
  output.integer_field = generate_record();\n\
}";

static FMStructDescList queue_list[] = {simple_format_list, NULL};

int main(int argc, char*argv[]) {
    //this is a two level tree, root, one level of parents and leaves. Each parent takes care of same number of leaves. 
    int active_parent = atoi(argv[3]);
    int leaf_num = atoi(argv[1]);
    //parents, leaves, and sink(root)
    int num_nodes = active_parent + leaf_num + 1; 
    printf("num_nodes %d\n", num_nodes);
    //the two extra, one for self, one for null
    
    //the first versanode id is "root" the localhost
    char **ids = new char*[num_nodes+1];  
    ids[0] = "root";
    //ids[1] = "root";
    //put all the active parents into ids
    FILE *dfgFile = fopen("/home/jli351/VersaScope/conf/parent_list", "r");
    if(dfgFile == NULL) printf("error! \n");
    
    int id_index = 1;
    for(; id_index <= active_parent; id_index++) {
      ids[id_index] = (char*)malloc(50*sizeof(char));
      fgets(ids[id_index], 50, dfgFile); 
      int length = strlen(ids[id_index]);
      ids[id_index][length-1] = '\0';
    }
    fclose(dfgFile);
    
    //put all the leaves into ids
    dfgFile = fopen(argv[2], "r");  
    if(dfgFile == NULL) printf("error opening leaf file! \n");
    for(; id_index <= active_parent + leaf_num ; id_index++) {
      ids[id_index] = (char*)malloc(50*sizeof(char));  
      fgets(ids[id_index], 50, dfgFile);
      int length = strlen(ids[id_index]);
      ids[id_index][length-1] = '\0';
      printf("%s\n", ids[id_index]);
    }
    fclose(dfgFile);
    ids[num_nodes] = NULL;
    int group_size = ceil(leaf_num*1.0/active_parent); 
    printf("%f group_size %d start register root\n", leaf_num*1.0/active_parent, group_size);
    
    //start the assignment procedure
    CManager cm;
    attr_list contact_list;
    char *str_contact;
    EVdfg_stone* nodes = new EVdfg_stone[num_nodes];

    cm = CManager_create();
    CMlisten(cm);
    contact_list = CMget_contact_list(cm);
    str_contact = attr_list_to_string(contact_list);
    
    test_dfg = EVdfg_create(cm);
    EVdfg_register_node_list(test_dfg, &ids[0]);
    
    printf("finished register root\n");
    int index = 0;
    
    char* filter = create_multityped_action_spec(queue_list, trans);
    nodes[index] = EVdfg_create_stone(test_dfg, filter);
    EVdfg_assign_node(nodes[index], ids[index]);
    index++;
    //assign parents
    for(; index <= active_parent ; index++) {
      printf("link parent %d\n", index);
      nodes[index] = EVdfg_create_stone(test_dfg, NULL);
      EVdfg_assign_node(nodes[index], ids[index]);
      EVdfg_link_port(nodes[index], 0, nodes[0]);//All the parents connect to the root
      printf("%d: %s -> %s \n", index, ids[index], ids[0]);
    } 
    //assign leaves
    int a = 1;
    for(; index < num_nodes; index++) {
      
      char *action_spec = create_transform_action_spec(NULL,simple_format_list,COD_generate);
      nodes[index] = EVdfg_create_stone(test_dfg, action_spec);
      EVdfg_assign_node(nodes[index], ids[index]);
      EVdfg_enable_auto_stone(nodes[index], 1, 0);

      int parent = (index - active_parent - 1)/group_size + 1;
      EVdfg_link_port(nodes[index], 0, nodes[parent]);//5 parents (1 to 5), 90 leaves (6 - 95), group_size 18,  
      printf("%d: %s -> %s \n", index, ids[index], ids[parent]);
      a++;
    }

    EVdfg_realize(test_dfg);
    
    char *file_name = "/root/VersaScope/conf/address";
    FILE *fptr = fopen(file_name, "w");
    fprintf(fptr, "%s\n", str_contact);
    fclose(fptr);
    printf("address %s\n", str_contact);
    EVdfg_join_dfg(test_dfg, "root", str_contact);
    printf("begin ready wait! \n");
    EVdfg_ready_wait(test_dfg);
    printf("return from ready wait!\n");
    CMrun_network(cm);
}
